﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Vds2465Telegrams
{
	public class UserData_50_DateAndTime : UserData
	{
		#region private member variables

		private readonly bool _includingSecond;
				
		private readonly byte _century;
		private readonly byte _year;
		private readonly byte _month;
		private readonly byte _day;
		private readonly byte _hour;
		private readonly byte _minute;
		private readonly byte _second;
		
		#endregion private member variables

		#region constructor

		/// <summary>
		/// Variant without seconds
		/// example date 23.03.2013 07:15 am -> constructor values: (20, 13, 03, 23, 07, 15)
		/// example date 13.08.1999 06:55 pm -> constructor values: (19, 99, 08, 13, 18, 55)
		/// </summary>
		public UserData_50_DateAndTime(byte century, byte year, byte month, byte day, byte hour, byte minute)
			: base(UserData.UserData50DateAndTime)
		{
			_includingSecond = false;

			_century = century;
			_year = year;
			_month = month;
			_day = day;
			_hour = hour;
			_minute = minute;
		}

		/// <summary>
		/// Variant including seconds
		/// example date 23.03.2013 07:15:30 am -> constructor values: (20, 13, 03, 23, 07, 15, 30)
		/// example date 13.08.1999 06:55:01 pm -> constructor values: (19, 99, 08, 13, 18, 55, 01)
		/// </summary>
		public UserData_50_DateAndTime(byte century, byte year, byte month, byte day, byte hour, byte minute, byte second)
			: base(UserData.UserData50DateAndTime)
		{
			_includingSecond = true;

			_century = century;
			_year = year;
			_month = month;
			_day = day;
			_hour = hour;
			_minute = minute;
			_second = second;
		}

		/// <summary>
		/// Variant using DateTime data type
		/// </summary>
		/// <param name="dateTime">the date and time value</param>
		/// <param name="includingSecond">true: the seconds value of dateTime is used, false: the seconds value is not used</param>
		public UserData_50_DateAndTime(DateTime dateTime, bool includingSecond)
			: base(UserData.UserData50DateAndTime)
		{
			_includingSecond = includingSecond;

			_century = (byte) (dateTime.Year / 100);
			_year = (byte)(dateTime.Year % 100);
			_month = (byte) dateTime.Month;
			_day = (byte)dateTime.Day;
			_hour = (byte)dateTime.Hour;
			_minute = (byte)dateTime.Minute;
			if (_includingSecond)
			{
				_second = (byte)dateTime.Second;
			}
		}

		#endregion constructor

		#region getters

		public bool IncludingSecond { get { return _includingSecond; } }

		public byte Century { get { return _century; } }
		public byte Year { get { return _year; } }

		public byte Month { get { return _month; } }
		public byte Day { get { return _day; } }

		public byte Hour { get { return _hour; } }
		public byte Minute { get { return _minute; } }

		/// <summary>
		/// Only returns a meaningful value if seconds are included
		/// </summary>
		public byte Second
		{ 
			get 
			{
				if (_includingSecond == false)
				{
					// TODO handle error - throw exception?
				}

				return _second; 
			} 
		}

		public DateTime DateAndTime 
		{ 
			get 
			{ 
				return new DateTime(_century*100 + _year, _month, _day, _hour, _minute, _second); 
			} 
		}

		#endregion getters

		#region ToString, Equals, GetHashCode

		public override int GetHashCode()
		{
			int hashCode = base.GetHashCode();

			hashCode ^= _century;
			hashCode ^= _year;
			hashCode ^= _month;
			hashCode ^= _day;
			hashCode ^= _hour;
			hashCode ^= _minute;
			hashCode ^= _second;

			if (_includingSecond)
			{
				hashCode ^= 0x01;
			}

			return hashCode;
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("(");
			stringBuilder.Append(ToStringProperties());
			stringBuilder.Append(")");

			return stringBuilder.ToString();
		}

		internal override string ToStringProperties()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(base.ToStringProperties());

			stringBuilder.Append(", ");

			stringBuilder.Append("DateAndTime='");
			stringBuilder.Append(DateAndTime.Year.ToString("d4"));
			stringBuilder.Append("-");
			stringBuilder.Append(DateAndTime.Month.ToString("d2"));
			stringBuilder.Append("-");
			stringBuilder.Append(DateAndTime.Day.ToString("d2"));
			stringBuilder.Append(" ");
			stringBuilder.Append(DateAndTime.Hour.ToString("d2"));
			stringBuilder.Append(":");
			stringBuilder.Append(DateAndTime.Minute.ToString("d2"));
			if (IncludingSecond)
			{
				stringBuilder.Append(":");
				stringBuilder.Append(DateAndTime.Second.ToString("d2"));
			}			
			stringBuilder.Append("'");

			return stringBuilder.ToString();
		}

		public override bool Equals(object obj)
		{
			Type objType = obj.GetType();
			if (this.GetType() == objType)
			{
				UserData_50_DateAndTime userData2Compare = obj as UserData_50_DateAndTime;
				return EqualsProperties(userData2Compare);
			}

			return false;
		}

		internal bool EqualsProperties(UserData_50_DateAndTime userData2Compare)
		{
			if (base.EqualsProperties(userData2Compare))
			{
				if (IncludingSecond == userData2Compare.IncludingSecond)
				{
					if (Century == userData2Compare.Century)
					{
						if (Year == userData2Compare.Year)
						{
							if (Month == userData2Compare.Month)
							{
								if (Day == userData2Compare.Day)
								{
									if (Hour == userData2Compare.Hour)
									{
										if (Minute == userData2Compare.Minute)
										{
											if (IncludingSecond)
											{
												return (Second == userData2Compare.Second);
											}

											return true;
										}

										return false;
									}

									return false;
								}

								return false;
							}

							return false;
						}

						return false;
					}

					return false;
				}

				return false;
			}

			return false;
		}

		#endregion ToString, Equals, GetHashCode
	}
}
